/**
 * This file is part of the CAKIS project.
 * 
 * Copyright (c) 2009-2010 - Florian Arndt, Christian Kerl
 * 
 * @license GNU Lesser General Public License v3 <http://www.opensource.org/licenses/lgpl-3.0.html>
 * @since   22.04.2010
 * @version SVN: $Id: HtmlContentHandlerExecutor.java 131 2010-05-13 22:12:31Z christian-kerl@web.de $
 */
package org.cakis.server.service.util;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;

import org.ccil.cowan.tagsoup.Parser;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

/**
 * HtmlContentHandlerExecutor provides methods to easily execute a {@link ContentHandler}
 * for an URL and retry on connection timeouts.
 *
 * @author Christian Kerl
 */
public class HtmlContentHandlerExecutor<T extends ContentHandler> {
    private final URLStreamFactory urls;
    private final T handler;
    private final String charset;
    private final XMLReader reader;

    public HtmlContentHandlerExecutor(URLStreamFactory urls, T handler, String charset) {
        this.urls = urls;
        this.handler = handler;
        this.charset = charset;

        this.reader = new Parser();
        this.reader.setContentHandler(handler);
    }

    public T execute(String url) {
        return execute(getUrl(url));
    }

    public T execute(URL url) {
        execute(url, 5);

        return handler;
    }

    private void execute(URL url, int repeat) {
        if(repeat > 0) {
            Reader input = null;
            try {
                input = getReaderForUrl(url);

                reader.parse(new InputSource(input));
            } catch (Exception e) {
                // TODO: replace with real Log
                System.out.println("[ContentHandlerExecutor]" + url);
                System.out.println("[ContentHandlerExecutor]" + e.getMessage());

                // timeout error
                if(e.getMessage().indexOf("timeout") > -1) {
                    execute(url, repeat - 1);
                }
            } finally {
                doSecureClose(input);
            }
        }
    }

    private URL getUrl(String url) {
        try {
            return new URL(url);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    private Reader getReaderForUrl(URL url) throws IOException {
        InputStream input = urls.openStream(url);

        return new BufferedReader(new InputStreamReader(input, charset));
    }

    private void doSecureClose(Closeable closable) {
        if(closable != null) {
            try {
                closable.close();
            } catch (IOException e) {
            }
        }
    }
}
